﻿package de.gameduell.framework.game.billard.model {
	import de.gameduell.framework.debug.Debug;
	import de.gameduell.framework.game.billard.event.SettingEvent;
	
	import flash.events.EventDispatcher;	

	/**
	 * @author cbra
	 */
	public class BillardSettings extends EventDispatcher {
			
		public static const KEY_MOVIE_FPS:String = "movie_fps";
		public static const KEY_ANIMATION_FPS:String = "fps";
		public static const KEY_MAX_SPEED:String = "maxSpeed";
		public static const KEY_MAX_EFFET:String = "maxEffet";
		public static const KEY_MAX_SPIN:String = "maxSpin";
		public static const KEY_GHOSTSTEPS_AFTER_COLLISION:String = "ghostStepsAfterCollision";

		public static const KEY_IMPULSE_SIGN:String = "impulseSign";
		public static const KEY_IMPULSE_WEIGHT_SELF:String = "impulseWeightSelf";
	   	public static const KEY_IMPULSE_WEIGHT_OTHER:String = "impulseWeightOther";
	   	
	   	public static const KEY_SPIN_SHIFT_FACTOR:String = "spinShiftFactor";
	   	public static const KEY_SPIN_ANGLE_SHIFT_FACTOR:String = "spinAngleShiftFactor";
	   	public static const KEY_SPIN_Z_TO_TRANSLATION_DIRECTION_CHANGE_FACTOR:String = "spinZToTranslationalDirectionChangeFactor";
	   	public static const KEY_SPIN_IMPULSE_ON_CONTACT_FACTOR:String = "spinImpulseOnContactFactor";
		
		public static const KEY_TRANSLATIONAL_FRICTION_EXP_XY:String = "translationalFrictionExpXY";
		public static const KEY_TRANSLATIONAL_FRICTION_LIN_XY:String = "translationalFrictionLinXY";
		public static const KEY_TRANSLATIONAL_FRICTION_CONST_XY:String = "translationalFrictionConstXY";
		
		public static const KEY_ROTATIONAL_FRICTION_EXP_Z:String = "rotationalFrictionExpZ";
		public static const KEY_ROTATIONAL_FRICTION_LIN_Z:String = "rotationalFrictionLinZ";
		public static const KEY_ROTATIONAL_FRICTION_CONST_Z:String = "rotationalFrictionConstZ";
		
		public static const KEY_ROTATIONAL_FRICTION_EXP_XY:String = "rotationalFrictionExpXY";
		public static const KEY_ROTATIONAL_FRICTION_LIN_XY:String = "rotationalFrictionLinXY";
		public static const KEY_ROTATIONAL_FRICTION_CONST_XY:String = "rotationalFrictionConstXY";
		
		public static const KEY_ROTATION_TO_TRANSLATION_CONVERSION_BY_ROLLING_EFFET_XY:String = "rotationToTranslationConversionByRollingEffetXY"; // effet around initial roll axis

		public static const KEY_HEAD_SHOOT_TRANSLATION_DRIFT:String = "headShootTranslationDrift";
		public static const KEY_HEAD_SHOOT_MINIMAL_SPEED:String = "headShootTranslationToRotationConversion";
		public static const KEY_HEAD_SHOOT_TRANSLATION_TO_ROTATION_CONVERSION:String = "headShootTranslationDrift";
		public static const KEY_HEAD_SHOOT_ANGLE_RANGE:String = "headShootAngleRange";
		
		public static const KEY_FADING_MAJOR_FRAMES_AFTER_CONTACT:String = "fadingMajorFramesAfterContact";
		public static const KEY_ROLL_ANGLE_SHIFT:String = "rollAngleShiftFactor";
		
		private static const INIT_ROLL_ANGLE_SHIFT:Number = 0.6;
		private static const INIT_FADING_MAJOR_FRAMES_AFTER_CONTACT:Number = 10;
  	
		
		private static const INIT_HEAD_SHOOT_TRANSLATION_DRIFT:Number = 0.5;
		private static const INIT_HEAD_SHOOT_MINIMAL_SPEED:Number = 0.0025;
		private static const INIT_HEAD_SHOOT_TRANSLATION_TO_ROTATION_CONVERSION:Number = 0.1;		
		private static const INIT_HEAD_SHOOT_ANGLE_RANGE:Number = 1;
		
		private static const INIT_MOVIE_FPS:Number = 80;
		private static const INIT_ANIMATION_FPS:Number = 200;
		private static const INIT_MAX_SPEED:Number = 40;
		private static const INIT_MAX_EFFET:Number = 0.5;
		private static const INIT_MAX_SPIN:Number = INIT_MAX_SPEED * INIT_MAX_EFFET;
		
		private static const INIT_GHOSTSTEPS_AFTER_COLLISION:int = 100;
		
		private static const INIT_IMPULSE_SIGN:Number = 1;
	   	private static const INIT_IMPULSE_WEIGHT_SELF:Number = 0.6;
	   	private static const INIT_IMPULSE_WEIGHT_OTHER:Number = 0.4; // mixed if more than one
		
	   	private static const INIT_SPIN_SHIFT_FACTOR:Number = -1;
	   	private static const INIT_SPIN_ANGLE_SHIFT_FACTOR:Number = 0.06;
	   	private static const INIT_SPIN_Z_TO_TRANSLATION_DIRECTION_CHANGE_FACTOR:Number = -1;
	   	private static const INIT_SPIN_IMPULSE_ON_CONTACT_FACTOR:Number = +0.005;
		
		private static const INIT_TRANSLATIONAL_FRICTION_EXP_XY:Number = 0.01;  
		private static const INIT_TRANSLATIONAL_FRICTION_LIN_XY:Number = 0.001;  
		private static const INIT_TRANSLATIONAL_FRICTION_CONST_XY:Number = 0.001;  
		
		private static const INIT_ROTATIONAL_FRICTION_EXP_Z:Number = 0.01;  
		private static const INIT_ROTATIONAL_FRICTION_LIN_Z:Number = 0.001;  
		private static const INIT_ROTATIONAL_FRICTION_CONST_Z:Number = 0.001;  
		
		private static const INIT_ROTATIONAL_FRICTION_EXP_XY:Number = 0.05; 
		private static const INIT_ROTATIONAL_FRICTION_LIN_XY:Number = 0.0005; 
		private static const INIT_ROTATIONAL_FRICTION_CONST_XY:Number = 0.005; 
		
		private static const INIT_ROTATION_TO_TRANSLATION_CONVERSION_BY_ROLLING_EFFET_XY:Number = 0.005;
		
		
		public static const KEY_NORMAL_ANIMATION_FPS:String = "normalFps";
		public static const KEY_NORMAL_MAX_SPEED:String = "normalMaxSpeed";
		
		private static const INIT_NORMAL_ANIMATION_FPS:Number = 200;
		private static const INIT_NORMAL_MAX_SPEED:Number = 10;
				
		public static const KEY_BREAK_ANIMATION_FPS:String = "breakFps";
		public static const KEY_BREAK_MAX_SPEED:String = "breakMaxSpeed";
		
		private static const INIT_BREAK_ANIMATION_FPS:Number = 150;
		private static const INIT_BREAK_MAX_SPEED:Number = 35;
			
		private var parameters:Array;
		private var _isBreakMode:Boolean;

		public function BillardSettings() {
			Debug.trace("BillardSettings:BillardSettings");
			parameters = new Array();
			
			parameters[KEY_MOVIE_FPS] = INIT_MOVIE_FPS;
			parameters[KEY_ANIMATION_FPS] = INIT_ANIMATION_FPS;
			parameters[KEY_MAX_SPEED] = INIT_MAX_SPEED;
			parameters[KEY_MAX_EFFET] = INIT_MAX_EFFET;
			parameters[KEY_GHOSTSTEPS_AFTER_COLLISION] = INIT_GHOSTSTEPS_AFTER_COLLISION;

			// init sphere values
			parameters[KEY_IMPULSE_SIGN] = INIT_IMPULSE_SIGN;
			parameters[KEY_IMPULSE_WEIGHT_SELF] = INIT_IMPULSE_WEIGHT_SELF;
			parameters[KEY_IMPULSE_WEIGHT_OTHER] = INIT_IMPULSE_WEIGHT_OTHER;
			parameters[KEY_SPIN_SHIFT_FACTOR] = INIT_SPIN_SHIFT_FACTOR;
			parameters[KEY_SPIN_ANGLE_SHIFT_FACTOR] = INIT_SPIN_ANGLE_SHIFT_FACTOR;
			parameters[KEY_SPIN_Z_TO_TRANSLATION_DIRECTION_CHANGE_FACTOR] = INIT_SPIN_Z_TO_TRANSLATION_DIRECTION_CHANGE_FACTOR;
			parameters[KEY_SPIN_IMPULSE_ON_CONTACT_FACTOR] = INIT_SPIN_IMPULSE_ON_CONTACT_FACTOR;
			parameters[KEY_TRANSLATIONAL_FRICTION_EXP_XY] = INIT_TRANSLATIONAL_FRICTION_EXP_XY;
			parameters[KEY_TRANSLATIONAL_FRICTION_LIN_XY] = INIT_TRANSLATIONAL_FRICTION_LIN_XY;
			parameters[KEY_TRANSLATIONAL_FRICTION_CONST_XY] = INIT_TRANSLATIONAL_FRICTION_CONST_XY;
			parameters[KEY_ROTATIONAL_FRICTION_EXP_Z] = INIT_ROTATIONAL_FRICTION_EXP_Z;
			parameters[KEY_ROTATIONAL_FRICTION_LIN_Z] = INIT_ROTATIONAL_FRICTION_LIN_Z;
			parameters[KEY_ROTATIONAL_FRICTION_CONST_Z] = INIT_ROTATIONAL_FRICTION_CONST_Z;
			parameters[KEY_ROTATIONAL_FRICTION_EXP_XY] = INIT_ROTATIONAL_FRICTION_EXP_XY;
			parameters[KEY_ROTATIONAL_FRICTION_LIN_XY] = INIT_ROTATIONAL_FRICTION_LIN_XY;
			parameters[KEY_ROTATIONAL_FRICTION_CONST_XY] = INIT_ROTATIONAL_FRICTION_CONST_XY;
			parameters[KEY_ROTATION_TO_TRANSLATION_CONVERSION_BY_ROLLING_EFFET_XY] = INIT_ROTATION_TO_TRANSLATION_CONVERSION_BY_ROLLING_EFFET_XY;		
			
			// head shoot params
			parameters[KEY_HEAD_SHOOT_MINIMAL_SPEED] = INIT_HEAD_SHOOT_MINIMAL_SPEED;
			parameters[KEY_HEAD_SHOOT_TRANSLATION_DRIFT] = INIT_HEAD_SHOOT_TRANSLATION_DRIFT;
			parameters[KEY_HEAD_SHOOT_TRANSLATION_TO_ROTATION_CONVERSION] = INIT_HEAD_SHOOT_TRANSLATION_TO_ROTATION_CONVERSION;
			parameters[KEY_HEAD_SHOOT_ANGLE_RANGE] = INIT_HEAD_SHOOT_ANGLE_RANGE;
			
			// max speed/spin
			parameters[KEY_MAX_SPIN] = INIT_MAX_SPIN;
			parameters[KEY_MAX_SPEED] = INIT_MAX_SPEED;
			
			parameters[KEY_NORMAL_ANIMATION_FPS] = INIT_NORMAL_ANIMATION_FPS;
			parameters[KEY_NORMAL_MAX_SPEED] = INIT_NORMAL_MAX_SPEED;
			
			parameters[KEY_BREAK_ANIMATION_FPS] = INIT_BREAK_ANIMATION_FPS;
			parameters[KEY_BREAK_MAX_SPEED] = INIT_BREAK_MAX_SPEED;	
			
			parameters[KEY_FADING_MAJOR_FRAMES_AFTER_CONTACT] = INIT_FADING_MAJOR_FRAMES_AFTER_CONTACT;
			parameters[KEY_ROLL_ANGLE_SHIFT] = INIT_ROLL_ANGLE_SHIFT;
//			switchToBreakMode();
			_isBreakMode = true;
			switchToNormalMode();
		}
		
		// updates the dependencies
		private function update():void{
			parameters[KEY_MAX_SPIN] = parameters[KEY_MAX_SPEED] * parameters[KEY_MAX_EFFET];
		}
		
		public function switchToBreakMode():void{	
			if(!_isBreakMode){
				Debug.trace("switchToBreakMode");
				setValue(KEY_MAX_SPEED,parameters[KEY_BREAK_MAX_SPEED]);
				setValue(KEY_ANIMATION_FPS,parameters[KEY_BREAK_ANIMATION_FPS]);
				_isBreakMode = true;
			}
		}
		
		public function switchToNormalMode():void{	
			if(_isBreakMode){
				Debug.trace("switchToNormalMode");
				setValue(KEY_MAX_SPEED,parameters[KEY_NORMAL_MAX_SPEED]);
				setValue(KEY_ANIMATION_FPS,parameters[KEY_NORMAL_ANIMATION_FPS]);
				_isBreakMode = false;
			}
		}
	
		public function parseXmlSettings(settings:XML):void{
			var nodes:XMLList = settings.children();

			for(var i:* in nodes) {
				var node:XML = XML(nodes[i]);
				var nodeName:String = node.name().localName;
				parameters[nodeName] = Number(node.toString());
			}
			update();	
			dispatchEvent(new SettingEvent(SettingEvent.LOADED));
		}
		
		public function isBreakMode():Boolean{
			return _isBreakMode;
		}

		/**
		 * generic getter
		 * BillardSetting.A_VALID_CONSTANT
		 */
		public function getValue(key:String):Number {
			// return result
			return parameters[key];
		}

		/**
		 * generic setter and event dispatch
		 * BillardSetting.A_VALID_CONSTANT
		 */
		public function setValue(key:String, value:String):void {
			// update
			parameters[key] = value;
			Debug.trace("setValue " +key+" "+value);
			// dispatch event
			update();	
			dispatchEvent(new SettingEvent(SettingEvent.CHANGED,key));
		}
		
	}
}
